# -*- coding: utf-8 -*-
# @Time    : 2024/7/8 11:27
# @Author  : wangwei
# @File    : webkeyword.py
import re
import time
import traceback

import pytest
from selenium import webdriver

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait
from msedge.selenium_tools import EdgeOptions

from common.Logger import logger
from common.decs import relations
from common.verify import get_verity
from get_path import get_pathdir


class WebKeyword:
    relations_dict = {}
    logger = logger
    driver=None

    def __int__(self):
        self.browser = None

        self.driver: webdriver.Chrome = None

    @relations
    def openbrowser(self, browser='chrome', remote_url=None):
        #remote_url="http://192.168.64.133:4444/wd/hub"
        self.browser = browser.lower()
        # 如果remote_url为None，说明你不连注册中心，要执行本地
        if remote_url:
            if self.browser == 'chrome':
                options = webdriver.ChromeOptions()
            elif self.browser == 'firefox':
                options = webdriver.FirefoxOptions()
            elif self.browser == 'ie':
                options = webdriver.IeOptions()
            elif self.browser == 'edge':
                options = EdgeOptions()
            else:
                self.logger.exception(f'不支持{self.browser}浏览器')

            self.logger.info(f'{self.browser}浏览器，通过远程打开成功')
            self.driver = webdriver.Remote(remote_url, desired_capabilities=options.to_capabilities())
        else:

            if self.browser == 'firefox' or self.browser == 'ff':
                self.driver = webdriver.Firefox()
            elif self.browser == 'ie':
                self.driver = webdriver.Ie()
            elif self.browser == 'edge':
                self.driver = webdriver.Edge()
            elif self.browser == 'safari':
                self.driver = webdriver.Safari()
            else:
                # 去掉自动化控制：
                self.browser = "chrome"
                option = Options()
                option.add_experimental_option('excludeSwitches', ['enable-automation'])
                option.add_argument("--disable-blink-features=AutomationControlled")
                # 实现不关闭的重点
                option.add_experimental_option("detach", True)
                # 关闭密码弹框：
                option.add_experimental_option("prefs", {
                    "download.prompt_for_download": False,
                    "download.directory_upgrade": True,
                    "safebrowsing.enabled": True,
                    "credentials_enable_service": False,
                    "profile.password_manager_enabled": False
                })
                option.add_experimental_option("excludeSwitches", ['enable-automation'])
                self.driver = webdriver.Chrome(options=option)
                self.logger.info(f'【{self.browser}】浏览器，本地打开成功打开成功')
        self.driver.implicitly_wait(10)  # 统一的隐式等待
        self.driver.maximize_window()

    @relations
    def geturl(self, url=""):
        try:
            self.driver.get(url)
            self.logger.info(f"成功访问网站【{url}】")
        except Exception as e:
            self.logger.exception(f"网站【{url}】访问网站失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def __find_ele(self, locator: str = ""):
        try:
            ele = self.driver.find_element(By.XPATH, locator)
            self.driver.execute_script("arguments[0].style.color='black'", ele)
            self.driver.execute_script("arguments[0].style.background='blue'", ele)
            self.logger.info(f"通过【{locator}】查找【元素】成功")
            return ele
        except Exception as e:
            self.logger.exception(f"通过【{locator}】查找【元素】失败，日志信息：" + str(traceback.format_exc()))
            return None

    @relations
    def find_elements(self, locator: str = ""):
        try:
            eles = self.driver.find_elements(By.XPATH, locator)
            self.logger.info(f"通过【{locator}】查找【多个元素列表】成功")
            return eles
        except Exception as e:
            self.logger.exception(f"通过【{locator}】查找【多个元素列表】失败，日志信息：" + str(traceback.format_exc()))
            return None

    @relations
    def click(self, locator: str = ""):
        try:
            wait = WebDriverWait(driver=self.driver, timeout=10)
            wait.until(click_to_success(locator))
            self.logger.info(f"通过【{locator}】执行【点击】操作成功")
        except Exception as e:
            self.logger.exception(f"通过【{locator}】执行【点击】操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def clear(self, locator: str = ''):
        try:
            ele = self.__find_ele(locator)
            ele.clear()
            self.logger.info(f"通过【{locator}】执行【清空】操作成功")
        except Exception as e:
            self.logger.exception(f"通过【{locator}】执行【清空】操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def input(self, locator: str = "", value=""):
        ele = self.__find_ele(locator)
        if value.endswith(".png") or value.endswith("jpg"):
            value = f"{get_pathdir}/{value}"
        ele.clear()
        ele.send_keys(value)
        self.logger.info(f"通过【locator】输入【{value}】操作成功")



    @relations
    def sleep(self, wait_time="1"):
        try:
            wait_time = float(wait_time)
            time.sleep(wait_time)
            self.logger.info(f"等待【{wait_time}s】，操作成功")
        except Exception as e:
            self.logger.exception(f"等待【{wait_time}s】，操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def intoiframe(self, locator: str = ""):
        try:
            if locator.startswith("/") or locator.startswith("("):
                ele = self.__find_ele(locator)
                self.driver.switch_to.frame(ele)
                self.logger.info(f"通过【XPATH】方式，定位元素：【{locator}】进入【iframe】中成功")
            else:
                self.driver.switch_to.frame(locator)
                self.logger.info(f"通过【ID】 或 【name】方式，定位元素：【{locator}】元素名，进入【iframe】中成功")
        except Exception as e:
            self.logger.exception(f"通过【{locator}】进入【iframe】中操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def outiframe(self):
        try:
            self.driver.switch_to.default_content()
            self.logger.info(f"退出【iframe】操作成功")
        except Exception as e:
            self.logger.exception(f"退出【iframe】操作中失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def refresh(self):
        try:
            self.driver.refresh()
            self.logger.info(f"【刷新】操作成功")
        except Exception as e:
            self.logger.exception(f"【刷新】操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def back(self):
        try:
            self.driver.back()
            self.logger.info(f"【返回】操作成功")
        except Exception as e:
            self.logger.exception(f"【返回】操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def forward(self):
        try:
            self.driver.forward()
            self.logger.info(f"【前进】操作成功")
        except Exception as e:
            self.logger.exception(f"【前进】操作失败，日志信息：" + str(traceback.format_exc()))

    @relations
    def assert_page_contains(self, text, timeout=5):
        try:
            wait = WebDriverWait(driver=self.driver, timeout=timeout)
            flag = wait.until(lambda d: text in d.page_source)
            self.logger.info(f"判断页面中包含文本内容【{text}】，结果是：True")
            return flag
        except BaseException as e:
            self.logger.exception(f"判断页面中包含文本内容【{text}】，结果是：False" )
            return False

    @relations
    def gettitle(self):
        try:
            title = self.driver.title
            self.relations_dict['title'] = title
            self.logger.info(f"【获取标题】操作成功")
            return title
        except Exception as e:
            self.logger.exception(f"【获取标题】操作失败，日志信息：" + str(traceback.format_exc()))
            return None

    @relations
    def gettext(self, lo: str = '', reg: str = ''):
        try:
            ele = self.__find_ele(lo)
            text = ele.text
            print(text)
            if reg:
                res = re.findall(reg, text)
                # 如果正则匹配成功就返回第一个匹配值
                if res:
                    text = res[0]
            # 存到关联里面
            self.relations_dict['text'] = text
            self.logger.info(f"通过元素【{lo}】查找文本值后，再根据正则表达式：【{reg}】获取值加入【全局变量】，操作成功")
            return text
        except Exception as e:
            self.logger.exception(f"通过元素【{lo}】查找文本值后，再根据正则表达式：【{reg}】获取值加入【全局变量】，操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def saveparam(self, key: str = '', value: str = ''):
        try:
            self.relations_dict[key] = value
            self.logger.info(f"通过key:【{key}】,value:【{value}】加入【全局变量】，操作成功")
        except Exception as e:
            self.logger.exception(f"通过key:【{key}】,value:【{value}】加入【全局变量】，操作失败，报错信息：" + str(traceback.format_exc()))


    @relations
    def hover(self, lo: str = ''):
        try:
            ele = self.__find_ele(lo)
            action = ActionChains(self.driver)
            # .perform()，让前面的一系列鼠标操作生效
            action.move_to_element(ele).perform()
            self.logger.info(f"通过元素定位方式:【{lo}】，执行【悬浮】操作成功")
        except Exception as e:
            self.logger.exception(f"通过元素定位方式:【{lo}】，执行【悬浮】操作失败，报错信息：" + str(traceback.format_exc()))




    @relations
    def select(self, lo: str = '', value: str = ''):
        try:
            ele = self.__find_ele(lo)
            se = Select(ele)
            try:
                # 如果是整数，就按下标取
                value = int(value)
                se.select_by_index(value)
            except:
                # 如果不是整数就按可见文本取
                se.select_by_visible_text(value)
            self.logger.info(f"通过元素定位方式:【{lo}】，值：【{value}】执行【选择】操作成功")
        except Exception as e:
            self.logger.exception(f"通过元素定位方式:【{lo}】，值：【{value}】执行【选择】操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def switchwin(self, winname: str = ''):
        try:
            window_handles = self.driver.window_handles
            for win in window_handles:
                self.driver.switch_to.window(win)
                title = self.gettitle()
                if title.__contains__(winname):
                    break
            self.logger.info(f"切换到窗口:【{winname}】，执行【窗口切换】操作成功")
        except Exception as e:
            self.logger.exception(f"切换到窗口:【{winname}】，执行【窗口切换】操作失败，报错信息：" + str(traceback.format_exc()))


    def js_click(self, lo: str = ''):
        try:
            ele = self.__find_ele(lo)
            self.driver.execute_script("argumenta[[0].click()", ele)
            self.logger.info(f"通过元素:【{lo}】，执行【js_click点击】操作成功")
        except Exception as e:
            self.logger.exception(f"通过元素:【{lo}】，执行【js_click点击】操作失败，报错信息：" + r)

    def js_input(self, lo: str = '', value=""):
        try:
            ele = self.__find_ele(lo)
            self.driver.execute_script(f"argumenta[[0].value={value}", ele)
            self.logger.info(f"通过元素:【{lo}】，输入值【{value}】，执行【js_input输入】操作成功")
        except Exception as e:
            self.logger.exception(f"通过元素:【{lo}】，输入值【{value}】，执行【js_input输入】操作失败，报错信息：" + str(traceback.format_exc()))


    def scroll_to(self, heigth=""):
        try:
            heigth = float(heigth)
            self.driver.execute_script(f"window.scrollTo(0,{heigth})")
            self.logger.info(f"通过js操作，滚动{heigth}距离，执行【js滚动】操作成功")
        except Exception as e:
            self.logger.exception(f"通过js操作，滚动{heigth}距离，执行【js滚动】操作失败，报错信息：" + str(traceback.format_exc()))

    def exec_script(self, script):
        try:
            self.driver.execute_script(script)
            self.logger.info(f"执行js脚本：【{script}】操作成功")
        except Exception as e:
            self.logger.exception(f"执行js脚本：【{script}】操作操作失败，报错信息：" + str(traceback.format_exc()))


    @relations
    def getverify(self, locator: str = '', filename=r"a.png"):
        try:
            ele = self.__find_ele(locator=locator)
            ele.screenshot(f'{filename}')
            verity = get_verity(rf'\{filename}')
            print("verity的值：" + verity)
            self.saveparam("verity", verity)
            print("self.relations_dict的值：" + str(self.relations_dict))
            self.logger.info(f"根据元素信息【{locator}】，保存为【{filename}】图片，存入【全局变量】操作成功")
        except Exception as e:
            self.logger.exception(f"通根据元素信息【{locator}】，保存为【{filename}】图片，存入【全局变量】操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def close(self):
        try:
            self.driver.quit()
            self.logger.info(f"【关闭浏览器】操作成功")
        except Exception as e:
            self.logger.exception(f"【关闭浏览器】操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def quit(self):
        try:
            self.driver.quit()
            self.logger.info(f"【退出浏览器】操作成功")
        except Exception as e:
            self.logger.exception(f"【退出浏览器】操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def get_screenshot_as_png(self):
        self.logger.info(f"【截图全屏】操作成功")
        return self.driver.get_screenshot_as_png()


    @relations
    def get_screenshot_as_file(self, filename):
        try:
            self.driver.get_screenshot_as_file(filename)
            self.logger.info(f"【截图全屏】，并保存到文件：【{filename}】中，操作成功")
        except Exception as e:
            self.logger.exception(f"【截图全屏】，并保存到文件：【{filename}】中，操作失败，报错信息：" + str(traceback.format_exc()))

    @relations
    def close_window_to_only_one(self):
        try:
            window_handles = self.driver.window_handles
            if len(window_handles) > 1:
                for i in range(1, len(window_handles)):
                    self.driver.switch_to.window(window_handles[i])
                    self.driver.close()
                self.driver.switch_to.window(window_handles[0])
            else:
                pass
            self.logger.info(f"【关闭窗口到仅剩一个窗口】操作成功")

        except Exception as e:
            self.logger.exception(f"【关闭窗口到仅剩一个窗口】操作失败，报错信息：" + str(traceback.format_exc()))


    @relations
    def assert_contains(self, act_res='', exp_res=''):

        if act_res.__contains__(exp_res):
            return True
        else:
            return False

    def myslide(self, lo=""):
        """12306滑块"""
        ele = self.__find_ele(lo)
        action = ActionChains(self.driver)
        action.move_to_element(ele).click_and_hold().move_by_offset(500, 0).perform()

    def tryclicks(self, lo: str = ''):
        try:
            ele = self.__find_ele(lo)
            ele.click()
        except:
            pass


class click_to_success(object):
    def __init__(self, locator):
        self.locator = locator

    def __call__(self, driver):
        try:
            element = driver.find_element(By.XPATH, self.locator)
            element.click()
            return True
        except:
            print('点击报错了')
            return False
